package com.gene.tlonpo.guard.tool;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.gene.tlonpo.converter.GuardConverter;
import com.gene.tlonpo.guard.Guard;
import com.gene.tlonpo.guard.GuardRequest;
import com.gene.tlonpo.guard.interf.GuardI;
import com.gene.tlonpo.manager.GuardDistributedManager;
import com.gene.tlonpo.manager.GuardLocalManager;
import com.gene.tlonpo.manager.TimeOutManager;
import com.gene.tlonpo.manager.interf.GuardManagerI;
import com.gene.tlonpo.manager.type.GuardManageType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.lang.NonNull;

/**
 * @author gene
 * 哨兵信息聚合处理工具
 * 提供哨兵处理相关的决策，编排工作
 */
@Slf4j
public class GuardAggregationTool {

    private static final Map<GuardManageType, GuardManagerI> MANAGER_I_LIST = new HashMap<>(16);

    static {
        MANAGER_I_LIST.put(GuardManageType.LOCAL, GuardLocalManager.INSTANCE);
        MANAGER_I_LIST.put(GuardManageType.DISTRIBUTED, GuardDistributedManager.INSTANCE);
        MANAGER_I_LIST.put(GuardManageType.TIMEOUT, TimeOutManager.INSTANCE);
    }

    /**
     * 添加哨兵
     *
     * @param guardRequest request
     */
    public static void addGuard(GuardRequest guardRequest) {
        guardReqValidate(guardRequest);
        Guard guard = GuardConverter.toGuard(guardRequest);
        MANAGER_I_LIST.values().forEach(manager -> manager.addGuard(guard));
    }

    /**
     * 移除哨兵
     * todo 需要特别说明的是：分布式环境下的guard移除存在一致性问题，在后续版本看是否能解决
     * todo 这也是为什么本组件适用于对一致性要求不高的情况下适用
     *
     * @param guard
     * @param type
     */
    public static void removeGuard(GuardI guard, GuardManageType type) {
        if (type == null) {
            log.warn("removeGuard do nothing,because the type is empty");
            return;
        }
        MANAGER_I_LIST.get(type).removeGuard(guard);
    }

    /**
     * 获取哨兵
     *
     * @param bizKey
     * @param guardId
     * @param type
     * @return
     */
    public static <T extends GuardI> T getGuard(String bizKey, String guardId, GuardManageType type) {
        if (Objects.isNull(type)) {
            throw new RuntimeException("type is null");
        }
        return MANAGER_I_LIST.get(type).getGuard(bizKey, guardId);
    }

    /**
     * 获取哨兵
     *
     * @param bizKey
     * @param type
     * @return
     */
    public static <T extends GuardI> List<T> getGuard(String bizKey, GuardManageType type) {
        if (Objects.isNull(type)) {
            throw new RuntimeException("type is null");
        }
        return MANAGER_I_LIST.get(type).getGuard(bizKey);
    }

    /**
     * 校验哨兵request
     *
     * @param guardRequest request
     */
    private static void guardReqValidate(GuardRequest guardRequest) {
        if (Objects.isNull(guardRequest)) {
            throw new NullPointerException("can not open guard,because of guardRequest is null");
        }
        guardRequest.selfValidate();
    }

}
